package com.hongawen.channel;

import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;

/**
 * @author hongawen
 * @version 1.0
 * @data 2025/4/30 9:44
 */
public class FileChannelTransfer {


    /**
     * 比较实用的工具。后期可以做成工具类。
     *
     * 简介：演示FileChannel的transferTo和transferFrom方法，底层实现原理是使用操作系统的零拷贝技术
     * <p>
     * 拷贝问题：文件不能超过2G，否则会仅仅转移2G的数据内容。
     * 长度问题：如果目标文件已经存在内容，并且长度超过源文件长度，那么仅会覆盖源文件长度的内容。根据实际情况去判断是否保留目标文件的内容。
     *
     * @param args .
     */
    public static void main(String[] args) {
        String from = System.getProperty("user.dir") + "/io/data.txt";
        String to = System.getProperty("user.dir") + "/io/new.txt";
        // 小文件
//        try(
//                RandomAccessFile fromFile = new RandomAccessFile(from, "r");
//                RandomAccessFile toFile = new RandomAccessFile(to, "rw");
//        ){
//            FileChannel fromChannel = fromFile.getChannel();
//            FileChannel toChannel = toFile.getChannel();
//            fromChannel.transferTo(0, fromChannel.size(), toChannel);
//        }catch (Exception exception){
//            exception.printStackTrace();
//        }

        // 大文件，通常指超过2G的文件
        try (
                RandomAccessFile fromFile = new RandomAccessFile(from, "r");
                RandomAccessFile toFile = new RandomAccessFile(to, "rw");
        ) {
            FileChannel fromChannel = fromFile.getChannel();
            FileChannel toChannel = toFile.getChannel();
            // 获取源文件的总大小（字节数），返回值是long类型，支持大文件（>2GB）
            long size = fromChannel.size();
            // left变量表示剩余需要传输的字节数，初始值为文件总大小
            // 循环条件：只要还有字节需要传输（left > 0）就继续
            for (long left = size; left > 0; ) {
                // 打印当前传输进度：
                // position = 总大小 - 剩余大小 = 已传输的字节数
                // left = 剩余需要传输的字节数
                System.out.println("position:" + (size - left) + " left:" + left);
                // 执行传输：
                // 参数1: (size - left) = 当前传输起始位置（从文件开头计算的偏移量）
                // 参数2: ※※※※※※※※※ left = 本次尝试传输的最大字节数 ※※※※※※※※※
                // 返回值: 实际传输的字节数（可能小于请求的left值）
                long transferred = fromChannel.transferTo(size - left, left, toChannel);
                // 减去本次实际传输的字节数
                left -= transferred;
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }


    }

}
